//== SAGITTARIUS ============================================================================

//== BEGINNING OF CODE ===============================================================

#include "sagittarius/core/SagittariusCore.h"

//SAGITTARIUS headers:
#include "sagittarius/re/reDC.h"
#include "sagittarius/io/io.h"

#include <malloc.h>
#include <string.h>

/// re_deepcopyDC
RE_DerivClass* re_deepcopyDC(const RE_DerivClass* d) {
    uint32 i;
	RE_DerivClass *r;
    AT(d->n > 0);
    r = LX_ALLOC(sizeof(RE_DerivClass) + (d->n-1)*sizeof(RE_CharSet*));
    r->n = d->n;
    for(i=0; i<d->n; ++i)
        r->s[i] = re_copyCS(d->s[i]);
    return r;
}

/// re_shallowcopyDC
RE_DerivClass* re_shallowcopyDC(const RE_DerivClass* d) {
    uint32 i;
	RE_DerivClass *r;
    AT(d->n > 0);
    r = LX_ALLOC(sizeof(RE_DerivClass) + (d->n-1)*sizeof(RE_CharSet*));
    r->n = d->n;
    for(i=0; i<d->n; ++i)
        r->s[i] = d->s[i];
    return r;
}

/// re_destroyDC
void re_destroyDC(RE_DerivClass* d) {
    uint32 i;
    AN(d);
    for(i=0;i<d->n;++i)
        re_destroyCS(d->s[i]);
    LX_FREE(d);
}

/// re_DCMesh
RE_DerivClass* re_DCFull() {
    RE_DerivClass *r = LX_ALLOC(sizeof(RE_DerivClass) + (0)*sizeof(RE_CharSet*)); //0 is a reminder
    r->n = 1;
    r->s[0] = re_createCSFull();
    return r;
}

/// re_DCSingle
RE_DerivClass* re_DCSingle(const RE_CharSet* s) {
    RE_DerivClass *r = LX_ALLOC(sizeof(RE_DerivClass) + (2-1)*sizeof(RE_CharSet*)); //2-1 is a reminder
    r->n = 2;
    r->s[0] = re_copyCS((RE_CharSet*)s); //had to get rid of const qualifiers because of GMP
    r->s[1] = re_CSComplement((RE_CharSet*)s);
    return r;
}

/// re_DCMesh
RE_DerivClass* re_DCMesh(const RE_DerivClass* p, const RE_DerivClass* q) {
    uint32 n=0;
    uint32 m = p->n*q->n;
    uint32 i=0,j=0;
	RE_CharSet** a;
	RE_DerivClass *r;

    AT(m > 0);
    //One case where use of malloc is okay
    //a gets freed before the function returns
    a = malloc(m*sizeof(RE_CharSet*)); //TODO: find a better way?
    
    for(i=0; i<p->n; ++i) {
        for(j=0; j<q->n; ++j) {
            //put all non-empty sets into a
            a[n] = re_CSIntersect(p->s[i], q->s[j]);
            if(!re_CSisEmpty(a[n]))
                n++;
            else
                re_destroyCS(a[n]);
        }
    }
    
    AT(n > 0);
    r = LX_ALLOC(sizeof(RE_DerivClass) + (n-1)*sizeof(RE_CharSet*));
    r->n = n;
    memcpy(r->s, a, n*sizeof(RE_CharSet*));
    free(a);
    return r;
}

/// re_writeDC
void re_writeDC(int fd, const RE_DerivClass* d) {
    uint32 i;
    SG_WRITE(fd, "DC{ ");
    for(i=0; i<d->n; ++i) {
        re_writeCS(fd, d->s[i]);
        if(i<d->n-1)
            SG_WRITE(fd, ", ");
    }
    SG_WRITE(fd, " }");
}
